#ifndef __CORE_COMMON_FILE_H_INCLUDE__
#define __CORE_COMMON_FILE_H_INCLUDE__

#include <core/common/platform.h>
#include <core/common/global.h>

namespace core{ namespace common
{
	class CORE_COMMON_API__ FileAttribute
	{
	public:
		bool   directory_;
		time_t createTime_;
		time_t modifyTime_;
		time_t accessTime_;
		int64  size_;

		FileAttribute();
	};

	typedef std::map<std::string, core::common::FileAttribute> FileAttributes;

	//
	// notice: all methods and functions,
	// all file path parameter can be input as "d:/path/name.ext" or "/path/name.ext"
	// while File::NormalizePath will convert it to platform format
	// for example, on Windows, "d:/path/name.ext" will be the same as "d:\path\name.ext"
	//

	class CORE_COMMON_API__ File
	{
	public:
		static const char  *kPathSeparator;
		static const char   kPathCharacter;
		static const uint64 kInvalidSize  = ((uint64)-1);
		static const size_t kMaxPathLength  = 256;

		typedef enum tagFILE_OPEN_MODE
		{
			kModeNone     = 0x00,
			kModeRead     = 0x01,
			kModeWrite    = 0x02,
			kModeText     = 0x04,
			kModeBinary   = 0x08,
			kModeLock     = 0x10,
		}FILE_OPEN_MODE;

		typedef enum tagFILE_SEEK_MODE
		{
			kSeekBegin     = 0x00,
			kSeekCurrent   = 0x01,
			kSeekEnd       = 0x02,
		}FILE_SEEK_MODE;

	private:
		FILE *handle_;
		int   openMode_;
		std::string file_;

		File( const File & ){}
		File &operator =( const File &file ){ return *this; }

	public:
		File();
		virtual ~File();

		//
		// directories
		//
		static bool makeDirectory( const std::string &path, int mode, bool recursion = false ); // mode is reserved for Linux
		static std::string getModulePath( void *param = NULL );
		static std::string getModuleDirectory( void *param = NULL );
		static std::string getTempDirectory();
		static std::string getNullDevicePath();
		static std::string getUserHomePath();
		static std::string getModuleAbsPath( const std::string &name );
		
		//
		// path or name
		//
		static bool isAbsolutePath( const std::string &path );
		static int  normalizeName( std::string &name, const std::string &replaceString = "_" );
		static int  normalizePath( std::string &path );
		static std::string normalizeNameTo( const std::string &name, const std::string &replaceString = "_" );
		static std::string normalizePathTo( const std::string &path );
		static std::string getNameFromPath( const std::string &path );
		static std::string getDirectoryFromPath( const std::string &path );
		static std::string getExtensionName( const std::string &path );

		//
		// file actions
		//
		static bool   moveFile( const std::string &source, const std::string &dest, bool overwrite = false );
		static bool   copyFile( const std::string &source, const std::string &dest, bool overwrite = true );
		static bool   copyDirectory( const std::string &source, const std::string &dest, bool overwrite = true );
		static bool   deleteFile( const std::string &file );
		static bool   deleteDirectory( const std::string &path, bool force = false );
		static bool   isExists( const std::string &file );
		static bool   isDirectoryEmpty( const std::string &path );
		static uint64 getSize( const std::string &file );
		static uint64 getSize( const int file );
		static bool   setSize( const std::string &file, uint64 newSize );
		static bool   setSize( const int file, uint64 newSize );
		
		//
		// file attributes
		//
		static core::common::FileAttribute getAttribue( const std::string &file );
		static bool   getAttribue( const std::string &file, core::common::FileAttribute &attr );
		static bool   getFileList( const std::string &directory, core::common::FileAttributes &files, bool fillAttr = true, size_t maxCount = 0 );

		//
		// object's methods
		//
		inline bool isOpened(){ return NULL != handle_; }
		inline bool isEndOfFile(){ return (NULL != handle_) && feof(handle_); }
		inline bool isError(){ return (NULL != handle_) && ferror(handle_); }
		inline void clearError(){ if( NULL != handle_ ) clearerr(handle_); } 

		bool   open( const std::string &file, int mode );
		bool   close();
		bool   flush();
		size_t read( void *buffer, size_t chunkSize, size_t count );
		size_t readHuge( void *buffer, size_t size, size_t blockSize = 10240 );
		bool   readLine( std::string &data, size_t maxCount );
		bool   readLine( char *buffer, size_t maxCount );
		size_t readData( std::string &data, size_t maxSize );
		size_t write( const void *buffer, size_t chunkSize, size_t count );
		size_t writeHuge( const void *buffer, size_t size, size_t blockSize = 10240 );
		size_t print( const char *format, ... ) __FMTCHECK__(printf, 2, 3);
		bool   seek( uint64 pos, int from );
		bool   setSize( uint64 newSize );
		uint64 getSize();
		uint64 getPosition();
		bool   lockRange( uint64 offset, uint64 size, bool toTry = false );
		bool   unlockRange( uint64 offset, uint64 size );
		FILE  *getHandle();
	};
}}

#endif //__CORE_COMMON_FILE_H_INCLUDE__
